#include "plateau.hpp"
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <time.h>

Cell::Cell() : valeurCell(0),statutCell(0)
{
}

char Cell::getValeurCell()
{
    return this->valeurCell;
}

char Cell::getStatutCell()
{
    return this->statutCell;
}

void Cell::setValeurCell(char valeur)
{
    this->valeurCell = valeur;
}

void Cell::setStatutCell(char statut)
{
    this->statutCell = statut;
}

Partie::Partie():nbTour(0)
{

    FILE *fichierModele  ;
    int i,j=0;
    char c;

    fichierModele = fopen("./res/dispoPlateau.txt","r");
    if (fichierModele != NULL)
    {
        for (i=0;i<15;i++)
        {
            while((c = getc(fichierModele))!= EOF && c!='\n')
            {
                this->grillePlateau[i][j].setStatutCell(c);
                this->grillePlateau[i][j].setValeurCell(' ');
                j++;
            }
            j=0;

        }
        remplirTabLettres(tabLettre);

        for(i=0;i<NB_JOUEUR_MAX;i++)
        {
            this->listeJoueur[i] = NULL;
        }
    }
    else
    {
        printf("Fichier modèle invalide !!");
    }
}

char Partie::getStatutCellGrille(int i,int j)
{
    return this->grillePlateau[i][j].getStatutCell();
}

int Partie::getValeurCellGrille(int i,int j)
{
    return this->grillePlateau[i][j].getValeurCell();
}

void Partie::setValeurCellGrille(char valeur,int i, int j)
{
    this->grillePlateau[i][j].setValeurCell(valeur);
}

void Partie::affichagePlateau()
{
    printf("  ");
    for(int k=0; k<DIMENSION_PLATEAU;k++)
    {
        if(k+1<10)
            printf("  %d  ",k+1);
        else
            printf("  %d ",k+1);
    }
    printf("\n");

    for(int i=0;i<15;i++)
    {
        printf("   ");
        for(int k=0; k<DIMENSION_PLATEAU;k++)
        {
            printf("-----");
        }
        printf("\n");

        if(i+1<10)
            printf("%d  ",i+1);
        else
            printf("%d ",i+1);

        for(int j=0;j<15;j++)
        {
            if(this->grillePlateau[i][j].getValeurCell() != ' ' && this->grillePlateau[i][j].getStatutCell() > 0 )
            {
                printf("| ");
                printf("%c",this->grillePlateau[i][j].getValeurCell());
                printf(" |");
            }
            else
            {
               switch(this->grillePlateau[i][j].getStatutCell())
                {
                    case '1':{
                            printf("|");
                            printf("Lx2");
                            printf("|");
                            break;
                        }
                    case '2':{
                            printf("|");
                            printf("Mx2");
                            printf("|");
                            break;
                        }
                    case '3':{
                            printf("|");
                            printf("Lx3");
                            printf("|");
                            break;
                        }
                    case '4':{
                            printf("|");
                            printf("Mx3");
                            printf("|");
                            break;
                        }
                    case '9':{
                            printf("| ");
                            printf("+");
                            printf(" |");
                            break;
                        }

                    default:{
                        printf("| ");
                        printf("%c",this->grillePlateau[i][j].getValeurCell());
                        printf(" |");
                        break;
                    }

                }
            }



        }
        printf("\n");

    }
    printf("   ");
    for(int k=0; k<DIMENSION_PLATEAU;k++)
        {
            printf("-----");
        }
    printf("\n");
    printf("\n");
}

int Partie::calculScore(int x, int y,string sens)
{
    int score=0,i=0,j=0,multiMot,multiLettre;
    multiMot=1;

    if(sens.at(0)=='v' || sens.at(0) =='V')
    {
        i=y-1;
        do
        {
            j=0;
            multiLettre=1;
            while(j<NB_LETTRES && this->getValeurCellGrille(i,x-1)!= this->tabLettre[j]->getCaractere())
            {
                j++;
            }
            switch(this->grillePlateau[i][x-1].getStatutCell())
            {
                case '1':{
                    multiLettre *= 2;
                    break;
                }
                case '2':{
                    multiMot *= 2;
                    break;
                }
                case '3':{
                    multiLettre *= 3;
                    break;
                }
                case '4':{
                    multiMot *= 3;
                    break;
                }

                default:{
                    multiLettre*=1;
                    multiMot*=1;
                    break;
                }
            }
            score += (this->tabLettre[j]->getValeur()*multiLettre);
            i++;
        }while(i<DIMENSION_PLATEAU && this->getValeurCellGrille(i,x-1)!= ' ');
    }
    else
    {
        i=x-1;
        do
        {
            j=0;
            multiLettre=1;
            while(j<NB_LETTRES && this->getValeurCellGrille(y-1,i)!= this->tabLettre[j]->getCaractere())
            {
                j++;
            }

            switch(this->grillePlateau[y-1][i].getStatutCell())
            {
                case '1':{
                    multiLettre *= 2;
                    break;
                }
                case '2':{
                    multiMot *= 2;
                    break;
                }
                case '3':{
                    multiLettre *= 3;
                    break;
                }
                case '4':{
                    multiMot *= 3;
                    break;
                }

                default:{
                    multiLettre*=1;
                    multiMot*=1;
                    break;
                }
            }
            score += (this->tabLettre[j]->getValeur()*multiLettre);
            i++;
        }while(i<DIMENSION_PLATEAU && this->getValeurCellGrille(y-1,i)!= ' ');
    }

    return score*multiMot;
}

void Partie::setNbJoueur(int n)
{
    this->nbJoueur = n;
}

int Partie::getNbJoueur()
{
    return this->nbJoueur;
}

void Partie::remplirChevalet(int numJoueur)
{
    char c;
    int i=0;
    while(i<TAILLE_CHEVALET && this->encoreDesLettres())
    {
        if((this->listeJoueur[numJoueur]->getCaractereChevalet(i)) == ' ')
        {
            do
            {
                c=randomLettre();
            }while( !this->lettreEstDispo(c));

            if(c>64 && c<91)
            {
                this->listeJoueur[numJoueur]->setCaractereChevalet(c,i);
                diminuerEffectifLettre(c);
            }
        }
    i++;
    }
    printf("\n");
}

int Partie::getNbTour()
{
    return this->nbTour;
}

int Partie::getScoreJoueurPartie(int num)
{
    return this->listeJoueur[num]->getScoreJoueur();
}

string Partie::getNomJoueurPartie(int num)
{
    return this->listeJoueur[num]->getNomJoueur();
}

void Partie::increNbTour()
{
    this->nbTour +=1;
}

bool Partie::encoreDesLettres() //Sert à vérifier qu'il reste encore des lettres
{
    int reste=0;
    for(int i=0;i<NB_LETTRES;i++)
    {
        if(this->tabLettre[i]->getEffectif()>0)
        {
            reste += this->tabLettre[i]->getEffectif();
        }
    }
    return reste>0;
}

bool Partie::insertionMotPlateau(string mot, int x, int y,char sens)
{
    bool correct=true;
    int superpositions=0;
    //Vérification de la validité du mot et des coordonnées pour que celui-ci n'empiète pas sur un mot différent sauf si le chevauchement se fait par une lettre commune
    // et qu'il existe au moins une superposition de caractères.
    if(sens =='V' || sens == 'v')
    {
        int i=y-1;
        while(i<y-1+mot.length() && correct)
        {
            if(this->getValeurCellGrille(i,x-1)==' ' || this->getValeurCellGrille(i,x-1) == normaliserCara(mot.at(i-(y-1))))
            {
                if(this->getValeurCellGrille(i,x-1) == normaliserCara(mot.at(i-(y-1))) || this->getStatutCellGrille(i,x-1)=='9')
                        superpositions+=1;
            }
            else
                correct=false;
            i++;
            }
    }
    else
    {
        int i=x-1;
        while(i<x-1+mot.length() && correct)
        {

            if(this->getValeurCellGrille(y-1,i)==' ' || this->getValeurCellGrille(y-1,i)==normaliserCara(mot.at(i-(x-1))))
            {
                if(this->getValeurCellGrille(y-1,i)==normaliserCara(mot.at(i-(x-1))) || this->getStatutCellGrille(y-1,i)=='9')
                    superpositions+=1;
            }
            else
            correct=false;
            i++;
        }
    }
    // Si les coordonnées et le mot sont validés, on entame l'écriture sur le plateau.
    if(correct && superpositions>0)
    {
        if(sens =='V' || sens == 'v')
        {
            int i=y-1;
            while(i<y-1+mot.length())
            {
                this->setValeurCellGrille(normaliserCara(mot.at(i-(y-1))),i,x-1);
                i++;
            }
        }
        else
        {
            int i=x-1;
            while(i<x-1+mot.length() && correct)
            {
                this->setValeurCellGrille(normaliserCara(mot.at(i-(x-1))),y-1,i);
                i++;
            }
        }
    }
    return correct;
}

void Partie::suppCaractereChevalet(int nJoueur,int nCaractere)
{
    this->listeJoueur[nJoueur]->setCaractereChevalet(' ',nCaractere);
}

void Partie::affichageChevaletPartie(int nJoueur)
{
    this->listeJoueur[nJoueur]->affichageChevaletJoueur();
}

void Partie::ajoutPointsScore(int numJoueur,int scoreSupp)
{
    this->listeJoueur[numJoueur]->ajoutPointScoreJoueur(scoreSupp);
}

bool Partie::lettreEstDispo(char c)
{
    int i=0;
    while (i<27 && c != this->tabLettre[i]->getCaractere())
    {
        i++;
    }
    return this->tabLettre[i]->getEffectif() > 0;
}

void Partie::diminuerEffectifLettre(char c)
{
    int i=0;

    while (i<27 && c != this->tabLettre[i]->getCaractere())
    {
        i++;
    }

    this->tabLettre[i]->setEffectif((this->tabLettre[i]->getEffectif())- 1);
}


void Partie::ajoutJoueurPartie(string nomJoueur)
{
    int i=0;
    while(this->listeJoueur[i] != NULL)
    {
        i++;
    }
    this->listeJoueur[i] = new Joueur(nomJoueur);
}

Joueur::Joueur():nomJoueur("default"),scoreJoueur(0)
{
    for(int i=0;i<TAILLE_CHEVALET;i++)
    {
        this->chevaletJoueur[i]=' ';
    }
}

Joueur::Joueur(string nom):nomJoueur(nom),scoreJoueur(0)
{
    for(int i=0;i<TAILLE_CHEVALET;i++)
    {
        this->chevaletJoueur[i]=' ';
    }
}

void Joueur::reinitScoreJoueur()
{
    this->scoreJoueur=0;
}

int Joueur::getScoreJoueur()
{
    return this->scoreJoueur;
}

string Joueur::getNomJoueur()
{
    return this->nomJoueur;
}

char Joueur::getCaractereChevalet(int i)
{
    return this->chevaletJoueur[i];
}

void Joueur::ajoutPointScoreJoueur(int scoreSupp)
{
    this->scoreJoueur += scoreSupp;
}

void Joueur::setNomJoueur(string nomNouveau)
{
    this->nomJoueur = nomNouveau;
}

void Joueur::affichageChevaletJoueur()
{
    for(int i=0;i<TAILLE_CHEVALET;i++)
    {
        printf("%c",this->chevaletJoueur[i]);
    }
}

void Joueur::setCaractereChevalet(char c, int i)
{
    this->chevaletJoueur[i] = c;
}

Lettre::Lettre():caractere(' '),effectif(0),valeur(0)
{
}

Lettre::Lettre(char c,int newEffectif,int newValeur):caractere(c),effectif(newEffectif),valeur(newValeur)
{
}

char Lettre::getCaractere()
{
    return this->caractere;
}

int Lettre::getValeur()
{
    return this->valeur;
}

int Lettre::getEffectif()
{
    return this->effectif;
}

void Lettre::setEffectif(int newEff)
{
    this->effectif = newEff;
}

bool chaineEstValide(string chaine)
{
    int i=0;
    while(i<chaine.size())
    {
        if(!((chaine.at(i)>64&&chaine.at(i)<91)||(chaine.at(i)>96&&chaine.at(i)<123)))
        {
            return false;
        }
        i++;
    }
    return true;
}

bool positionEstValide(int x,int y,string mot,string sens)
{
    if(sens.at(0)=='v' || sens.at(0)=='V')
    {
        return ((mot.length()-1)+y)<= DIMENSION_PLATEAU;
    }
    else
    {
        return ((mot.length()-1)+x)<= DIMENSION_PLATEAU;
    }
}

string lireEntreeClavierChaine()
{
    string str="";
    cin >> str;
    return str;
}

int lireEntreeClavierEntier()
{
    int nb=0;
    scanf("%d",&nb);
    return nb;
}

char randomLettre()
{

    return rand()%26+65;
}

char normaliserCara(char c)
{
    if(c>96)
        return c-32;
    else
        return c;
}

void remplirTabLettres(Lettre *tabLettre[NB_LETTRES])
{
    tabLettre[0] = new Lettre('A',9,1);
    tabLettre[1] = new Lettre('B',2,3);
    tabLettre[2] = new Lettre('C',2,3);
    tabLettre[3] = new Lettre('D',3,2);
    tabLettre[4] = new Lettre('E',15,1);
    tabLettre[5] = new Lettre('F',2,4);
    tabLettre[6] = new Lettre('G',2,2);
    tabLettre[7] = new Lettre('H',2,4);
    tabLettre[8] = new Lettre('I',8,1);
    tabLettre[9] = new Lettre('J',1,8);
    tabLettre[10] = new Lettre('K',1,10);
    tabLettre[11] = new Lettre('L',6,1);
    tabLettre[12] = new Lettre('M',3,2);
    tabLettre[13] = new Lettre('N',6,1);
    tabLettre[14] = new Lettre('O',6,1);
    tabLettre[15] = new Lettre('P',2,3);
    tabLettre[16] = new Lettre('Q',1,8);
    tabLettre[17] = new Lettre('R',6,1);
    tabLettre[18] = new Lettre('S',6,1);
    tabLettre[19] = new Lettre('T',6,1);
    tabLettre[20] = new Lettre('U',6,1);
    tabLettre[21] = new Lettre('V',2,4);
    tabLettre[22] = new Lettre('W',1,10);
    tabLettre[23] = new Lettre('X',1,10);
    tabLettre[24] = new Lettre('Y',1,10);
    tabLettre[25] = new Lettre('Z',1,10);
    tabLettre[26] = new Lettre('*',2,0);

}




